#!/usr/bin/python3
##################################################
'''数值和表达式转换为字符串'''
# Copyright (c) 2022 Xu Ruijun | 1687701765@qq.com
# the file is MIT License
##################################################
import math

__author__ = "Xu Ruijun"
__copyright__ = "Copyright (c) 2022 Xu Ruijun"
__license__ = "MIT"


sup_num = '⁰¹²³⁴⁵⁶⁷⁸⁹⁺⁻⁼⁽⁾'
sub_num = '₀₁₂₃₄₅₆₇₈₉₊₋₌₍₎'
norm_num = '0123456789+-=()'

prefix = ['', 'k', 'M', 'G', 'T', 'P', 'f', 'p', 'n', 'μ', 'm']
prefix_dict = {
'f':-5, 'p':-4, 'n':-3, 'μ':-2, 'm':-1, 'k':1, 'M':2, 'G':3, 'T':4, 'P':5,
                'N':-3, 'u':-2,         'K':1,        'g':3,
                        'U':-2,
}

def itoa_rep(x, rep):
    assert isinstance(x, int)
    s = str(x)
    ret = []
    for ch in s:
        i = norm_num.find(ch)
        ret.append(rep[i])
    return ''.join(ret)

def itoa_sup(x):
    return itoa_rep(x, sup_num)

def itoa_sub(x):
    return itoa_rep(x, sub_num)

def hand_num_sci(x, digs=3):
    tail, exp = f'{x:.{digs-1}e}'.split('e')
    exp = itoa_sup(int(exp))
    return f'{tail}×10{exp}'

def hand_num_auto(x, sdigs=3, fdigs=4, i_th=10000, f_l=0.1, f_h=10000):
    if isinstance(x, int):
        if x < i_th:
            return str(x)
        else:
            return hand_num_sci(x, sdigs)
    elif isinstance(x, float):
        if f_l <= x < f_h:
            n = len(str(abs(x)))
            xdigs = fdigs - n
            return f'{x:.{xdigs}f}'
        else:
            return hand_num_sci(x, sdigs)
    else:
        raise TypeError(f'type(x)={type(x)}')

def num_SIprefix(x, res_len=5, ox=True):
    # 计算小数点后保留几位数字
    xdigs = res_len - 3
    if x < 0:
        xdigs -= 1
    if 1 <= abs(x) < 1000:
        xdigs += 1
    # 使用f-string格式化字符串（自带四舍五入）
    Mant, exp = f'{x:.{xdigs}e}'.split('e')
    exp = int(exp)
    level = exp//3
    assert -5 <= level <= 5
    # 改变小数点位置
    lM = list(Mant)
    lM.remove('.')
    pointx = exp - level*3 + 1
    if ox and exp == -1:
        # 0.xxx 保留前置零
        lM.insert(0, '0')
        pointx = 1
        level = 0
    lM.insert(pointx, '.')
    xM = ''.join(lM)
    # 取后缀词头
    pre = prefix[level]
    ret = xM + pre
    return ret

def poly2str(coeffs, var='x', spt=' ', coef_func=hand_num_auto):
    Items = []
    for xexp, coef in enumerate(coeffs):
        exp = len(coeffs) - xexp - 1
        # sign char
        if coef == 0:
            continue
        elif xexp == 0:
            pass
        elif coef < 0:
            Items.append('-')
            coef = -coef
        else:
            Items.append('+')
        #coef_str
        if coef == 1 and exp != 0:
            coef_str = ''   # 非常数项系数的绝对值为1时
        elif coef == -1 and xexp == 0:
            coef_str = '-'  # 第一项的系数为-1时
        else:
            coef_str = coef_func(coef)  # 其他情况
        # tail str
        if exp > 1:
            tail_str = var+itoa_sup(exp)
        elif exp == 1:
            tail_str = var
        elif exp == 0: 
            tail_str = ''
        else:
            raise ValueError
        # merge
        item = coef_str+tail_str
        Items.append(item)
    return spt.join(Items)

def frac2str(b, a, lch='─', *args, **kwargs):
    B = poly2str(b, *args, **kwargs)
    A = poly2str(a, *args, **kwargs)
    width = max(len(B), len(A))
    A = A.center(width)
    B = B.center(width)
    line = lch*math.ceil(width/len(lch))
    #return f'{B}\n{line}\n{A}'
    return B, line, A  # 方便后面处理
